package com.ssy.invoicing.dao.support;

import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.ibatis.SqlMapClientCallback;
import org.springframework.orm.ibatis.SqlMapClientTemplate;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapExecutor;
import com.ssy.invoicing.common.constant.Constant;
import com.ssy.invoicing.common.util.PageParam;

/**
 * 基本的SQL操作对象，此类存放了系统中一些通用的方法。 <br>
 * 方便使用ibatis，可以将具体Dao继承此类。
 * @author suoyao.shen
 */
@SuppressWarnings({"deprecation","rawtypes","unchecked"})
public class BaseSqlDao extends SqlMapClientDaoSupport implements IBaseSqlData {

    private Logger                 log4j = Logger.getLogger(BaseSqlDao.class);
    
    @SuppressWarnings("unused")
    @Autowired
    private void injectSqlMapClient(SqlMapClient sqlMapClient) {
       setSqlMapClient(sqlMapClient);
    }

    protected SqlMapClientTemplate smct  = getSqlMapClientTemplate();

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#delete(java.lang.
     * String, java.lang.Object, int)
     */

    public void delete(String statementName, Object parameterObject, int requiredRowsAffected)
            throws DataAccessException {
        smct.delete(statementName, parameterObject, requiredRowsAffected);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#delete(java.lang.
     * String, java.lang.Object)
     */

    public int delete(String statementName, Object parameterObject) throws DataAccessException {

        return smct.delete(statementName, parameterObject);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#delete(java.lang.
     * String)
     */

    public int delete(String statementName) throws DataAccessException {

        return smct.delete(statementName);
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.orm.ibatis.SqlMapClientTemplate#execute(org.
     * springframework.orm.ibatis.SqlMapClientCallback)
     */

    public Object execute(SqlMapClientCallback arg0) throws DataAccessException {

        return smct.execute(arg0);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#executeWithListResult
     * (org.springframework.orm.ibatis.SqlMapClientCallback)
     */

    public List<?> executeWithListResult(SqlMapClientCallback action) throws DataAccessException {

        return smct.executeWithListResult(action);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#executeWithMapResult
     * (org.springframework.orm.ibatis.SqlMapClientCallback)
     */

    public Map<?,?> executeWithMapResult(SqlMapClientCallback action) throws DataAccessException {

        return smct.executeWithMapResult(action);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#insert(java.lang.
     * String, java.lang.Object)
     */

    public Object insert(String statementName, Object parameterObject) throws DataAccessException {
        return smct.insert(statementName, parameterObject);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#insert(java.lang.
     * String)
     */

    public Object insert(String statementName) throws DataAccessException {
        return smct.insert(statementName);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#queryForList(java
     * .lang.String, int, int)
     */

    public List<?> queryForList(String statementName, int skipResults, int maxResults)
            throws DataAccessException {
        return smct.queryForList(statementName, skipResults, maxResults);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#queryForList(java
     * .lang.String, java.lang.Object, int, int)
     */

    public List<?> queryForList(String statementName, Object parameterObject, int skipResults,
                             int maxResults) throws DataAccessException {
        return smct.queryForList(statementName, parameterObject, skipResults, maxResults);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#queryForList(java
     * .lang.String, java.lang.Object)
     */

    public List<?> queryForList(String statementName, Object parameterObject)
            throws DataAccessException {
        return smct.queryForList(statementName, parameterObject);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#queryForList(java
     * .lang.String)
     */

    public List<?> queryForList(String statementName) throws DataAccessException {
        return smct.queryForList(statementName);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#queryForMap(java.
     * lang.String, java.lang.Object, java.lang.String, java.lang.String)
     */

    public Map<?,?> queryForMap(String statementName, Object parameterObject, String keyProperty,
                           String valueProperty) throws DataAccessException {
        return smct.queryForMap(statementName, parameterObject, keyProperty, valueProperty);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#queryForMap(java.
     * lang.String, java.lang.Object, java.lang.String)
     */

    public Map<?,?> queryForMap(String statementName, Object parameterObject, String keyProperty)
            throws DataAccessException {
        return smct.queryForMap(statementName, parameterObject, keyProperty);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#queryForObject(java
     * .lang.String, java.lang.Object, java.lang.Object)
     */

    public Object queryForObject(String statementName, Object parameterObject, Object resultObject)
            throws DataAccessException {
        return smct.queryForObject(statementName, parameterObject, resultObject);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#queryForObject(java
     * .lang.String, java.lang.Object)
     */

    public Object queryForObject(String statementName, Object parameterObject)
            throws DataAccessException {
        return smct.queryForObject(statementName, parameterObject);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#queryForObject(java
     * .lang.String)
     */

    public Object queryForObject(String statementName) throws DataAccessException {
        return smct.queryForObject(statementName);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#update(java.lang.
     * String, java.lang.Object, int)
     */

    public void update(String statementName, Object parameterObject, int requiredRowsAffected)
            throws DataAccessException {
        smct.update(statementName, parameterObject, requiredRowsAffected);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#update(java.lang.
     * String, java.lang.Object)
     */

    public int update(String statementName, Object parameterObject) throws DataAccessException {
        return smct.update(statementName, parameterObject);
    }

    /*
     * (non-Javadoc)
     * @see
     * org.springframework.orm.ibatis.SqlMapClientTemplate#update(java.lang.
     * String)
     */
    public int update(String statementName) throws DataAccessException {
        return smct.update(statementName);
    }

    /**
     * 分页查询
     * 
     * @param statementName 查询语句，在SQLMap配置文件中，<b>参数类型需要设置为java.util.HashMap</b>。因为需要利用Map传递分页的参数
     * @param countStatementName 统计总数的语句，参数类型可以不变
     * @param parameterObject 包含查询参数的对象，如果此对象不是Map的实例，则会新建一个map来包装此参数，key为：paramObj
     * @param pageNo 需要查询的页码
     * @return
     */
    public SplitPageResult queryListByPagination(String statementName, String countStatementName,
                                                 Object parameterObject, int pageNo)
            throws SQLException {

        SplitPageResult spr = new SplitPageResult();

        PageParam pageParam = new PageParam();
        pageParam.setPageSize(Constant.DEFAULT_LIST_PAGE_SIZE);
        pageParam.setPage(pageNo);

        long begin = System.currentTimeMillis();
        Integer count = (Integer) queryForObject(countStatementName, parameterObject);
        long cost = System.currentTimeMillis() - begin;
        if(cost > 1000) {
            log4j.error(String.format("TOO SLOW to count num of MailSendReceiveInfo, for %s, cost %s millis", ((Map)parameterObject).get("accountNo"), cost));
        }
        begin = System.currentTimeMillis();
        
        if (count != null && count.longValue() > 0) {
            pageParam.reset(pageParam.getPage(), count.intValue());

            
            Map param;
            //如果参数是Map的实例，则直接将分页参数设置进入Map
            if(parameterObject instanceof Map){
                param = (Map)parameterObject;
            }else{ //如果不是，则新建一个Map，以传递分页参数
                param = new HashMap<String, Object>();
                param.put("paramObj", parameterObject);
            }
            param.put("rowBegin4SplitPage", pageParam.getFirstRowNum());
            param.put("size4SplitPage", Constant.DEFAULT_LIST_PAGE_SIZE);
            spr.setResult(queryForList(statementName, param));
        } else {
            // 重置总记录数
            pageParam.reset(pageParam.getPage(), 0);
            spr.setResult(Collections.emptyList());
        }
        spr.setPagination(pageParam);
        
        cost = System.currentTimeMillis() - begin;
        if(cost > 1000) {
            log4j.error(String.format("TOO SLOW to select data of MailSendReceiveInfo, for %s, cost %s millis", ((Map)parameterObject).get("accountNo"), cost));
        }
        
        return spr;
    }

    /**
     * query page information
     * @author wb_zhaoyuwei
     * @param statementName sql: data of page displayed
     * @param countStatementName sql: data of page count
     * @param parameterObject  map<String, Object>:parameter               
     * @param pageNo page number
     * @param pageSize  record number of every page displayed  
     * @return
     * @throws SQLException
     */
    public SplitPageResult queryListByPagination(String  statementName, 
    											 String  countStatementName,
                                                 Object  parameterObject, 
                                                 Integer pageNo, 
                                                 Integer everyCount) throws SQLException {

        SplitPageResult spr = new SplitPageResult();


        long begin = System.currentTimeMillis();
        Integer count = (Integer) queryForObject(countStatementName, parameterObject);
        long cost = System.currentTimeMillis() - begin;
        if(cost > 1000) {
            log4j.error(String.format("TOO SLOW to count num of MailSendReceiveInfo, for %s, cost %s millis", ((Map)parameterObject).get("accountNo"), cost));
        }
        begin = System.currentTimeMillis();
        
        if (count != null && count.longValue() > 0) {
            PageParam pageParam = new PageParam(pageNo, everyCount, count.intValue());
            Map param;
            //如果参数是Map的实例，则直接将分页参数设置进入Map
            if(parameterObject instanceof Map){
                param = (Map)parameterObject;
            }else{ //如果不是，则新建一个Map，以传递分页参数
                param = new HashMap<String, Object>();
                param.put("paramObj", parameterObject);
            }
            
            param.put("rowBegin4SplitPage", pageParam.getFirstRowNum());
            param.put("size4SplitPage", everyCount);
            spr.setResult(queryForList(statementName, param));
            spr.setPagination(pageParam);
        } else {
            // 重置总记录数
        	 PageParam pageParam = new  PageParam(pageNo, everyCount, 0);        	
            spr.setResult(Collections.emptyList());
            spr.setPagination(pageParam);
        }
        
        cost = System.currentTimeMillis() - begin;
        if(cost > 1000) {
            log4j.error(String.format("TOO SLOW to select data of MailSendReceiveInfo, for %s, cost %s millis", ((Map)parameterObject).get("accountNo"), cost));
        }
        
        return spr;
    }

    /**
     * 批量插入
     * @param sql
     * @param list
     */
    public void insertBatch(final String sql, final List<? extends Object> list){
    	smct.execute(new SqlMapClientCallback(){
			@Override
			public Object doInSqlMapClient(SqlMapExecutor executor)
					throws SQLException {
				executor.startBatch();
				 for(int i=0,count=list.size();i<count;i++){
					 executor.insert(sql, list.get(i));
				 }
				 executor.executeBatch();
				return null;
			}
    	});
    }
    /**
     * 分页查询结果
     * 
     * @author ZhaoYu.Jin
     * @history <br>
     *          <ol>
     *          <li>2011-5-25 ZhaoYu.Jin Created</li>
     *          </ol>
     */
    public static class SplitPageResult {
        private PageParam pagination;
        private List<?>      result;

        /**
         * @return the pagination
         */
        public PageParam getPagination() {
            return pagination;
        }

        /**
         * @param pagination the pagination to set
         */
        public void setPagination(PageParam pagination) {
            this.pagination = pagination;
        }

        /**
         * @return the result
         */
        public List<?> getResult() {
            return result;
        }

        /**
         * @param result the result to set
         */
        public void setResult(List<?> result) {
            this.result = result;
        }

    }
}
